package org.nicocube.airain.domain.client.gamedate;

import java.io.Serializable;

import org.nicocube.airain.domain.client.data.Storable;

public class GameDate extends AbstractGameDate implements Storable,Serializable,Comparable<GameDate> {

	private static final long serialVersionUID = 1L;

	protected long timestamp;
	
	// needed by GWT !
	protected GameDate(){}
	
	protected GameDate(long begin, long end) {
		timestamp = end - begin;
	}
	
	public GameDate(int h,int d,int m,long y) {
		if (h==0) throw new RuntimeException("hour 0 is forbidden");
		if (d==0) throw new RuntimeException("day 0 is forbidden");
		if (m==0) throw new RuntimeException("moon 0 is forbidden");
		if (y==0) throw new RuntimeException("year 0 is forbidden");
		timestamp =
			(h>0?h-1:h)*game_hours_seconds +
			(d>0?d-1:d)*game_day_seconds +
			(m>0?m-1:m)*game_moon_seconds+
			(y>0?y-1:y)*game_year_seconds;
	}
	
	public GameDate(AbstractGameDate other) {
		this.timestamp = other.getTimestamp();
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append(cardinalization(getHours())).append(" hour, ")
		  .append(cardinalization(getMoonDays())).append(" day, ")
		  .append(cardinalization(getYearMoons())).append(" moon, ")
		  .append(cardinalization(getYears())).append(" ").append(getSeason());
		return sb.toString();
	}

	protected String cardinalization(long val) {
		return String.valueOf(val)+cardinal(val);
	}
	
	protected String cardinal(long val) {
		switch ((int)val%100) {
		case 11:
		case 12:
		case 13:
			return "th";
		}
		switch ((int)val%10) {
		case 1:
			return "st";
		case 2:
			return "nd";
		case 3:
			return "rd";
		default:
			return "th";
		}
	}

	public int getHours() {
		return (int)((getTimestamp()-((getTotalDays()-1)*game_day_seconds)) / game_hours_seconds) +1;
	}
	
	public int getMoonDays() {
		return (int)((getYearDays()-1) % 28)+1;
	}
	
	public int getYearDays() {
		return (int)((getTotalDays()-1) % (28*12))+1;
	}
	
	public long getTotalDays() {
		return (getTimestamp() / game_day_seconds)+1;
	}
	
	public int getYearMoons() {
		return (int) (getTotalMoons() % 12)+1;
	}
	
	public long getTotalMoons() {
		return getTimestamp() / game_moon_seconds;
	}
	
	public long getYears() {
		return (getTotalMoons() / 12)+1;
	}
	
	public Season getSeason() {
		return Season.values()[(getYearMoons()-1)/3];
	}

	public long getTimestamp() {
		return timestamp;
	}
	
	protected void setTimestamp(long timestamp) {
		this.timestamp = timestamp;
	}
	
	@Override
	public boolean equals(Object obj) {
		GameDate otherdate = (GameDate)obj;
		return getTimestamp() == otherdate.getTimestamp();
	}
	
	@Override
	public int hashCode() {
		return new Long(getTimestamp()).hashCode();
	}

	//@Override
	public int compareTo(GameDate o) {
		return new Long(getTimestamp()).compareTo(o.getTimestamp());
	}
}
